package oneplay.YonghongBITools;

import oneplay.YonghongBITools.HttpClientUtils.RequestInstance;
import org.apache.commons.io.IOUtils;
import org.jdom2.JDOMException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// 接口注意事项
// 1. 每个接口会在请求参数栏标明请求参数是否必填。若请求参数为无，则不需要填写请求参数；若请求参数为必填，则需要填写请求参数；
// 2. 每个接口的参数描述栏会详细标明请求参数中的参数是否为必填项。若为必填项，请填写对应的内容；若为选填项，则可填可不填，但是仍然需要写出对应标签。

public class YHWebAPI {
    private static final Logger logger = LoggerFactory.getLogger(YHWebAPI.class);

    private final RequestInstance requestInstance;

    private final String URL_API;
    private String token = "";

    public static final String SUCCESS = "1";
    public static final String WARN = "5";
    public static final String ERROR = "6";

    public YHWebAPI(String URL_API) {
        this.URL_API = URL_API;
        requestInstance = new RequestInstance(URL_API.startsWith("https"));
    }

    /**
     * 登陆认证
     * 此接口只是用来进行api验证用，不能用来进行单点登录
     *
     * @param adminv 用户名
     * @param passv  密码
     * @return 结果
     */
    public boolean login(String adminv, String passv) {
        if (!token.isEmpty()) {
            logout();
        }
        try {
            HashMap<String, String> data = new HashMap<String, String>() {{
                put("action", "login");
                put("adminv", adminv);
                put("passv", passv);
            }};
            XMLDocument xmlDocument = new XMLDocument(requestInstance.post(URL_API, data));
            String result = getLevel(xmlDocument);
            String message = getMessage(xmlDocument);
            if (SUCCESS.equals(result)) {
                token = message;
                return true;
            } else {
                logger.error(String.format("YonghongAPI login failed. %s", message));
            }
        } catch (JDOMException | IOException e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 退出登陆
     */
    public void logout() {
        try {
            HashMap<String, String> data = new HashMap<String, String>() {{
                put("action", "logout");
                put("token", token);
            }};
            XMLDocument xmlDocument = new XMLDocument(requestInstance.post(URL_API, data));
            String result = getLevel(xmlDocument);
            String message = getMessage(xmlDocument);
            if (SUCCESS.equals(result)) {
                token = "";
            } else {
                logger.warn(String.format("YonghongAPI logout failed. %s", message));
            }
        } catch (JDOMException | IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

    private String getLevel(XMLDocument xmlDocument) {
        return xmlDocument.getFirstElementText("/results/result/level");
    }

    private String getMessage(XMLDocument xmlDocument) {
        return xmlDocument.getFirstElementText("/results/result/message");
    }

    /**
     * 获取报告血缘信息
     */
    public XMLDocument getReportLineage(String path) {
        HashMap<String, String> data = new HashMap<>();
        data.put("action", "getDbLineage");
        data.put("token", token);
        data.put("xmlData", String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><info><user></user><getdata>" +
                "<dbpath>%s</dbpath>" +
                "<type>1</type>" + // 报告类型：1-普通报告 2-DBLink（包含收藏的报告、分享的报告、我的报告）
                "</getdata></info>", path));
        try {
            XMLDocument responseXML = new XMLDocument(requestInstance.post(URL_API, data));
            logErrorResponse(responseXML);
            return responseXML;
        } catch (JDOMException | IOException e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    /**
     * 递归获取指定文件夹列表数据
     */
    public List<String> getReportList(String path, boolean recursive) {
        HashMap<String, String> data = new HashMap<>();
        data.put("action", "updateTree");
        data.put("token", token);
        data.put("xmlData", String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><info>\n" +
                "<opens></opens>\n" +
                "<folders>%s</folders>\n" +
                "</info>", path));
        List<String> reportList = new ArrayList<>();
        try {
            XMLDocument responseXML = new XMLDocument(requestInstance.post(URL_API, data));
            logErrorResponse(responseXML);
            List<String> dbList = responseXML.getElementsValueText("/results/result/assetref/children/result/assetref[type=\"db\"]/path");
            reportList.addAll(dbList);
            if (recursive) {
                List<String> folderList = responseXML.getElementsValueText("/results/result/assetref/children/result/assetref[type=\"folder\"]/path");
                for (String folder : folderList) {
                    reportList.addAll(getReportList(folder, true));
                }
            }
        } catch (JDOMException | IOException e) {
            logger.error(e.getMessage(), e);
        }
        return reportList;
    }

    public byte[] downloadFile(String path, Map<String, String> params) throws IOException {
        HashMap<String, String> data = new HashMap<>();
        data.put("action", "downloadFile");
        data.put("token", token);
        data.put("xmlData", String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?><info>\n" +
                "<rptPath>%s</rptPath>\n" +
                "<fileType>xls</fileType>\n" +
                "<params>%s</params>\n" +
                "</info>", path, getParams(params)));
        return requestInstance.postForBin(URL_API, data);
    }

    private String getParams(Map<String, String> params) {
        StringBuilder stringBuilder = new StringBuilder();
        params.forEach((k, v) -> stringBuilder.append(String.format("<param name=\"%s\" type=\"string\">%s</param> ", k, v)));
        return stringBuilder.toString();
    }

    private void logErrorResponse(XMLDocument xmlDocument) {
        String level = getLevel(xmlDocument);
        if (level != null && !SUCCESS.equals(level)) {
            logger.error(xmlDocument.toString());
        }
    }

}
